// 中央通信中心

class CommandCenter {
    constructor() {
        this.handlers = new Map();
        this.listeners = new Map();
    }

    /**
     * 注册一个命令处理
     * @param {string} command 
     * @param {(args: any, context: object) => any | Promise | AsyncGenerator} handler 
     */
    register(command, handler) {
        this.handlers.set(command, handler);
    }

    /**
     * 分发一个指令
     * @param {{ command: string, args?: any, stream?: boolean, id?: string, source?: string, token?: string }} payload 
     * @param {'internal' | Window} origin 
     */
    async emit(payload, origin = 'internal') {
        const handler = this.handlers.get(payload.command);
        if (!handler) {
            console.warn(`[CommandCenter] 未找到处理器: ${payload.command}`);
            return;
        }

        let hasResponded = false;

        const context = {
            id: payload.id,
            token: payload.token,
            source: payload.source || 'unknown',
            originType: (origin === 'internal' ? 'internal' : 'iframe'),
            reply: (data) => {
                hasResponded = true;
                this.respond(payload.command, data, origin, false, payload.id, payload.source);
            },
            stream: (chunk) => {
                hasResponded = true;
                this.respond(payload.command, chunk, origin, true, payload.id, payload.source);
            },
            end: (data) => {
                hasResponded = true;
                this.respond(payload.command, { status: '[END]', data: data }, origin, false, payload.id, payload.source);
            }
        };

        const result = handler(payload.args, context);

        if (result && typeof result === 'object' && typeof result[Symbol.asyncIterator] === 'function') {
            for await (const chunk of result) {
                context.stream(chunk);
            }
            context.end();
        } else if (result instanceof Promise) {
            const awaited = await result;
            if (!hasResponded && awaited !== undefined) {
                context.reply(awaited);
            }
        } else if (!hasResponded && result !== undefined) {
            context.reply(result);
        }
    }

    /**
     * 监听响应（推荐用于虚拟终端或控制区）
     * @param {string} command 
     * @param {(data: any, isStream: boolean, id: string, source: string) => void} callback 
     */
    on(command, callback) {
        const handler = (e) => {
            callback(e.detail.data, e.detail.isStream, e.detail.id, e.detail.source);
        };
        if (!this.listeners.has(command)) {
            this.listeners.set(command, new Map());
        }
        this.listeners.get(command).set(callback, handler);
        window.addEventListener(`cmd:${command}`, handler);
    }

    off(command, callback) {
        const map = this.listeners.get(command);
        if (!map) return;
        const handler = map.get(callback);
        if (handler) {
            window.removeEventListener(`cmd:${command}`, handler);
            map.delete(callback);
        }
        if (map.size === 0) {
            this.listeners.delete(command);
        }
    }

    once(command, callback) {
        const handler = (e) => {
            callback(e.detail.data, e.detail.isStream, e.detail.id, e.detail.source);
            if (e.detail.data?.status === '[END]') {
                this.off(command, callback);
            }
        };
        if (!this.listeners.has(command)) {
            this.listeners.set(command, new Map());
        }
        this.listeners.get(command).set(callback, handler);
        window.addEventListener(`cmd:${command}`, handler);
    }

    /**
     * 响应发送者
     * @param {string} command 
     * @param {any} data 
     * @param {'internal' | Window} origin 
     * @param {boolean} isStream
     * @param {string} id
     * @param {string} source
     * @param {string} token
     */
    respond(command, data, origin, isStream = false, id, source, token) {
        if (origin === 'internal') {
            window.dispatchEvent(new CustomEvent(`cmd:${command}`, {
                detail: { data, isStream, id, source, token }
            }));
        } else {
            const safeData = JSON.parse(JSON.stringify(data));
            origin.postMessage({
                type: 'iframeCommandResponse',
                command,
                data: safeData,
                isStream,
                id,
                source,
                token
            }, '*');
        }
    }

    /**
     * 启用来自 iframe 的消息监听
     */
    messageListener = (event) => {
        if (event.data?.type === 'iframeCommandDispatch') {
            this.emit(event.data.payload, event.source);
        } else if (event.data?.type === 'iframeCommandResponse') {
            window.dispatchEvent(new CustomEvent(`cmd:${event.data.command}`, {
                detail: { data: event.data.data, isStream: event.data.isStream, id: event.data.id, source: event.data.source, token: event.data.token }
            }));
        }
    }
    listenIframeMessage() {
        window.addEventListener('message', this.messageListener);
    }
    /**
     * 取消来自 iframe 的消息监听
     */
    unlistenIframeMessage() {
        window.removeEventListener('message', this.messageListener);
    }

    /**
     * 向 iframe 发送指令
     * @param {Window} targetWindow 
     * @param {{ command: string, args?: any, stream?: boolean, source?: string, token?: string }} payload 
     */
    sendToIframe(targetWindow, payload) {
        targetWindow.postMessage({ type: 'iframeCommandDispatch', payload }, '*');
    }

    /**
     * iframe 向主窗口发送指令（如果不在 iframe 中则不发送）
     * @param {{ command: string, args?: any, stream?: boolean, source?: string, token?: string }} payload
     */
    sendToParent(payload) {
        if (window.parent !== window) {
            window.parent.postMessage({ type: 'iframeCommandDispatch', payload }, '*');
        } else {
            console.warn('[CommandCenter] 当前不是 iframe 环境，忽略 sendToParent');
        }
    }
}

export const CommandCenterInstance = new CommandCenter();